﻿using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ALMDDD.AspNetCore.Redis
{
    public class OperateWithRedis
    {
        #region Server

        /// <summary>
        /// 删除指定数据库的所有key
        /// Delete all the keys of the database.
        /// </summary>
        /// <param name="dbIndex">数据库序号</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        public static void FlushDbFun(int dbIndex = 0, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IServer server = ConMultiplexerHelper.GetServer(connectionMultiplexer);
            server.FlushDatabaseAsync(dbIndex, flags);
        }

        /// <summary>
        /// 删除所有数据库的所有key
        /// Delete all the keys of all databases on the server.
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// </summary>
        public static void FlushAllDbFun(CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IServer server = ConMultiplexerHelper.GetServer(connectionMultiplexer);
            server.FlushAllDatabasesAsync(flags);
        }

        #endregion

        #region Key

        /// <summary>
        /// 查找所有符合给定模式 pattern 的 key 。KEYS * 匹配数据库中所有 key 。特殊符号用 \ 隔开。
        /// KEYS h?llo 匹配 hello ， hallo 和 hxllo 等。KEYS h*llo 匹配 hllo 和 heeeeello 等。KEYS h[ae]llo 匹配 hello 和 hallo ，但不匹配 hillo 。
        /// </summary>
        /// <param name="pattern">模糊搜索</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <returns>Returns the values of all specified keys.</returns>
        public static RedisValue[] KeyScanFun(RedisValue pattern, int dbIndex = 0, int pageSize = 10, long cursor = 0, int pageOffset = 0, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);
            IServer server = ConMultiplexerHelper.GetServer(connectionMultiplexer);

            //Returns all keys matching pattern.
            RedisKey[] ks = server.Keys(db.Database, "*" + pattern + "*", pageSize, cursor, pageOffset, flags).ToArray();

            //Returns the values of all specified keys. For every key that does not hold
            //a string value or does not exist, the special value nil is returned.
            RedisValue[] vs = connectionMultiplexer.Wait(db.StringGetAsync(ks, flags));

            return vs;
        }

        /// <summary>
        /// 设置一个key的过期的秒数，为给定 key 设置生存时间，当 key 过期时(生存时间为 0 )，它会被自动删除。
        /// 生存时间可以通过使用 DEL 命令来删除整个 key 来移除，或者被 SET 和 GETSET 命令覆写(overwrite)，这意味着，
        /// 如果一个命令只是修改(alter)一个带生存时间的 key 的值而不是用一个新的 key 值来代替(replace)它的话，那么生存时间不会被改变。
        ///比如说，对一个 key 执行 INCR 命令，对一个列表进行 LPUSH 命令，或者对一个哈希表执行 HSET 命令，这类操作都不会修改 key 本身的生存时间。
        ///另一方面，如果使用 RENAME 对一个 key 进行改名，那么改名后的 key 的生存时间和改名前一样。
        ///RENAME 命令的另一种可能是，尝试将一个带生存时间的 key 改名成另一个带生存时间的 another_key，这时旧的 another_key (以及它的生存时间)会被删除，
        ///然后旧的 key 会改名为 another_key ，因此，新的 another_key 的生存时间也和原本的 key 一样。
        ///使用 PERSIST 命令可以在不删除 key 的情况下，移除 key 的生存时间，让 key 重新成为一个『持久的』(persistent) key 。
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="expiry">时间间隔</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <returns>1 if the timeout was set. 0 if key does not exist or the timeout could not be set.</returns>
        public static bool KeyExpireFun(RedisKey key, TimeSpan? expiry, int dbIndex = 0, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);
            return connectionMultiplexer.Wait(db.KeyExpireAsync(key, expiry, flags));
        }

        /// <summary>
        /// 设置一个key的过期的秒数，为给定 key 设置生存时间，当 key 过期时(生存时间为 0 )，它会被自动删除。
        /// 生存时间可以通过使用 DEL 命令来删除整个 key 来移除，或者被 SET 和 GETSET 命令覆写(overwrite)，这意味着，
        /// 如果一个命令只是修改(alter)一个带生存时间的 key 的值而不是用一个新的 key 值来代替(replace)它的话，那么生存时间不会被改变。
        ///比如说，对一个 key 执行 INCR 命令，对一个列表进行 LPUSH 命令，或者对一个哈希表执行 HSET 命令，这类操作都不会修改 key 本身的生存时间。
        ///另一方面，如果使用 RENAME 对一个 key 进行改名，那么改名后的 key 的生存时间和改名前一样。
        ///RENAME 命令的另一种可能是，尝试将一个带生存时间的 key 改名成另一个带生存时间的 another_key，这时旧的 another_key (以及它的生存时间)会被删除，
        ///然后旧的 key 会改名为 another_key ，因此，新的 another_key 的生存时间也和原本的 key 一样。
        ///使用 PERSIST 命令可以在不删除 key 的情况下，移除 key 的生存时间，让 key 重新成为一个『持久的』(persistent) key 。
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="expiry">时间间隔</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <returns>1 if the timeout was set. 0 if key does not exist or the timeout could not be set.</returns>
        public static bool KeyExpireFun(RedisKey key, DateTime? expiry, int dbIndex = 0, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);
            return connectionMultiplexer.Wait(db.KeyExpireAsync(key, expiry, flags));
        }

        /// <summary>
        /// 移除给定 key 的生存时间，将这个 key 从『易失的』(带生存时间 key )转换成『持久的』(一个不带生存时间、永不过期的 key)。
        /// Remove the existing timeout on key, turning the key from volatile (a key with an expire set) 
        /// to persistent (a key that will never expire as no timeout is associated).
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <returns>1 if the timeout was removed. 0 if key does not exist or does not have an associated timeout.</returns>
        public static bool KeyPersistFun(RedisKey key, int dbIndex = 0, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);
            return connectionMultiplexer.Wait(db.KeyPersistAsync(key, flags));
        }

        /// <summary>
        /// 移除指定的key
        /// Removes the specified key. A key is ignored if it does not exist.
        /// </summary>
        /// <param name="key">要移除的key</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <returns>True if the key was removed.</returns>
        public static bool KeyDeleteFun(RedisKey key, int dbIndex = 0, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);
            return connectionMultiplexer.Wait(db.KeyDeleteAsync(key, flags));
        }

        /// <summary>
        /// 移除指定的keys
        /// Removes the specified keys. A key is ignored if it does not exist.
        /// </summary>
        /// <param name="keys">要移除的keys</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <returns>The number of keys that were removed.</returns>
        public static long KeyDeleteFun(RedisKey[] keys, int dbIndex = 0, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);
            return connectionMultiplexer.Wait(db.KeyDeleteAsync(keys, flags));
        }

        /// <summary>
        /// 将key改名为newkey，当key和newkey相同，或者key不存在时，返回一个错误。当newkey已经存在时，RENAME命令将覆盖旧值。
        /// Renames key to newkey. It returns an error when the source and destination names are the same, or when key does not exist.
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="newKey">新的键</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <param name="when">Indicates when this operation should be performed</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <returns>改名成功时提示OK，失败时候返回一个错误。</returns>
        public static bool KeyRenameFun(RedisKey key, RedisKey newKey, int dbIndex = 0, When when = When.Always, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);
            return connectionMultiplexer.Wait(db.KeyRenameAsync(key, newKey, when, flags));
        }

        /// <summary>
        /// 将当前数据库的 key 移动到给定的数据库 db 当中。如果当前数据库(源数据库)和给定数据库(目标数据库)
        /// 有相同名字的给定 key，或者 key 不存在于当前数据库，那么 MOVE 没有任何效果。
        /// Move key from the currently selected database (see SELECT) to the specified destination database. 
        /// When key already exists in the destination database, or it does not exist in the source database, it does nothing. 
        /// It is possible to use MOVE as a locking primitive because of this.
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="dbIndexNew">目标数据库序号</param>
        /// <param name="dbIndex">当前数据库序号</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <returns>1 if key was moved; 0 if key was not moved.</returns>
        public static bool KeyMoveFun(RedisKey key, int dbIndexNew, int dbIndex = 0, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);
            return connectionMultiplexer.Wait(db.KeyMoveAsync(key, dbIndexNew, flags));
        }

        /// <summary>
        /// 检查给定 key 是否存在。
        /// Returns if key exists.
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <returns>1 if the key exists. 0 if the key does not exist.</returns>
        public static bool KeyExistsFun(RedisKey key, int dbIndex = 0, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);
            return connectionMultiplexer.Wait(db.KeyExistsAsync(key, flags));
        }

        #endregion

        #region String

        /// <summary>
        /// 设置一个key的value值
        /// Set key to hold the string value. If key already holds a value, it is overwritten, regardless of its type.
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="value">值</param>
        /// <param name="expiry">时间间隔</param>
        /// <param name="when">Indicates when this operation should be performed</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <returns>True if the keys were set, else False</returns>
        public static bool StringSetFun(RedisKey key, RedisValue value, int dbIndex = 0, TimeSpan? expiry = null, When when = When.Always, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);
            return connectionMultiplexer.Wait(db.StringSetAsync(key, value, expiry, when, flags));
        }

        /// <summary>
        /// 设置多个key value
        /// Sets the given keys to their respective values. If "not exists" is specified,
        /// this will not perform any operation at all even if just a single key already exists.
        /// </summary>
        /// <param name="values">多个key value</param>
        /// <param name="when">Indicates when this operation should be performed</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <returns>True if the keys were set, else False</returns>
        public static bool StringSetFun(KeyValuePair<RedisKey, RedisValue>[] values, int dbIndex = 0, When when = When.Always, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);
            return connectionMultiplexer.Wait(db.StringSetAsync(values, when, flags));
        }

        /// <summary>
        /// 获取key的值
        /// Get the value of key. If the key does not exist the special value nil is returned. 
        /// An error is returned if the value stored at key is not a string, because GET only handles string values.
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <returns> the value of key, or nil when key does not exist.</returns>
        public static RedisValue StringGetAsyncFun(RedisKey key, int dbIndex = 0, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);
            return connectionMultiplexer.Wait(db.StringGetAsync(key, flags));
        }

        /// <summary>
        /// 获得所有keys的值
        /// Returns the values of all specified keys. For every key that does not hold 
        /// a string value or does not exist, the special value nil is returned.
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <returns>指定的keys对应的values的list</returns>
        public static RedisValue[] StringGetAsyncFun(RedisKey[] keys, int dbIndex = 0, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);
            return connectionMultiplexer.Wait(db.StringGetAsync(keys, flags));
        }

        /// <summary>
        /// Returns the length of the string value stored at key.
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <returns>the length of the string at key, or 0 when key does not exist.</returns>
        public static long StringLengthAsync(RedisKey key, int dbIndex = 0, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);
            return connectionMultiplexer.Wait(db.StringLengthAsync(key, flags));
        }

        #endregion

        #region Set

        /// <summary>
        /// 将一个 member 元素加入到集合 key 当中，已经存在于集合的 member 元素将被忽略。
        /// Add the specified member to the set stored at key. Specified members that
        /// are already a member of this set are ignored. If key does not exist, a new
        /// set is created before adding the specified members.
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="theVal">一个 member 元素</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <returns>True if the specified member was not already present in the set, else False.</returns>
        public static bool SetAddFun(RedisKey key, RedisValue value, int dbIndex = 0, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);
            return connectionMultiplexer.Wait(db.SetAddAsync(key, value, flags));
        }

        /// <summary>
        /// 将多个 member 元素加入到集合 key 当中，已经存在于集合的 member 元素将被忽略。
        /// Add the specified members to the set stored at key. Specified members that are already a member of this set are ignored. 
        /// If key does not exist, a new set is created before adding the specified members.
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="values">多个 member 元素</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <returns>the number of elements that were added to the set, not including all the elements already present into the set.</returns>
        public static long SetAddFun(RedisKey key, RedisValue[] values, int dbIndex = 0, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);
            return connectionMultiplexer.Wait(db.SetAddAsync(key, values, flags));
        }

        /// <summary>
        /// 根据key获取所对应的Set的元素个数
        /// Returns the set cardinality (number of elements) of the set stored at key.
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <returns>the cardinality (number of elements) of the set, or 0 if key does not exist.</returns>
        public static long SetLengthFun(RedisKey key, int dbIndex = 0, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);
            return connectionMultiplexer.Wait(db.SetLengthAsync(key, flags));
        }

        /// <summary>
        /// 模糊搜索指定key所对应的members
        /// The SSCAN command is used to incrementally iterate over set
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="pattern">模糊搜索</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        public static RedisValue[] SetScanFun(RedisKey key, RedisValue pattern, int dbIndex = 0, int pageSize = 10, long cursor = 0, int pageOffset = 0, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);
            IServer server = ConMultiplexerHelper.GetServer(connectionMultiplexer);
            RedisValue[] rv = null;

            if (server.Features.Scan)
            {
                rv = db.SetScan(key, "*" + pattern + "*", pageSize, cursor, pageOffset, flags).ToArray();
            }
            return rv;
        }

        /// <summary>
        /// 返回集合 key 中的所有成员。不存在的 key 被视为空集合。(Set、SortedSet通用)
        /// Returns all the members of the set value stored at key.
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <returns>all elements of the set.</returns>
        public static RedisValue[] SetMembersFun(RedisKey key, int dbIndex = 0, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);
            RedisValue[] rv = connectionMultiplexer.Wait(db.SetMembersAsync(key, flags));
            return rv;
        }

        #endregion

        #region SortSet

        /// <summary>
        /// 将一个 member 元素及其 score 值加入到有序集 key 当中。如果某个 member 已经是有序集的成员，
        /// 那么更新这个 member 的 score 值，并通过重新插入这个 member 元素，来保证该 member 在正确的位置上。
        /// （注意：直接用SortedSetScan无法对这种经过序列化的对象的SortedSet进行排序遍历，你会发现它们是无序的，
        /// 可能原因是序列化之后出现冒号，如果theVal不是一个序列化对象，而是一个简答的字符串，
        /// 则可以用SortedSetScan进行遍历，它们是有序的，否则只能用SortedSetRangeByRank进行遍历）
        /// Adds the specified member with the specified score to the sorted set stored
        /// at key. If the specified member is already a member of the sorted set, the
        /// score is updated and the element reinserted at the right position to ensure the correct ordering.
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="member">一个 member 元素</param>
        /// <param name="score">分数的值,score 值可以是整数值或双精度浮点数。</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <returns>True if the value was added, False if it already existed (the score is still updated)</returns>
        public static bool SortedSetAddFun(RedisKey key, RedisValue member, double score, int dbIndex = 0, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);
            return connectionMultiplexer.Wait(db.SortedSetAddAsync(key, member, score, flags));
        }

        /// <summary>
        /// 将多个 member 元素及其 score 值加入到有序集 key 当中。如果某个 member 已经是有序集的成员，
        /// 那么更新这个 member 的 score 值，并通过重新插入这个 member 元素，来保证该 member 在正确的位置上。
        /// （注意：直接用SortedSetScan无法对这种经过序列化的对象的SortedSet进行排序遍历，你会发现它们是无序的，
        /// 可能原因是序列化之后出现冒号，如果theVal不是一个序列化对象，而是一个简答的字符串，
        /// 则可以用SortedSetScan进行遍历，它们是有序的，否则只能用SortedSetRangeByRank进行遍历）
        /// Adds the specified member with the specified score to the sorted set stored
        /// at key. If the specified member is already a member of the sorted set, the
        /// score is updated and the element reinserted at the right position to ensure the correct ordering.
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="values">多个 member 元素</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <returns>The number of elements added to the sorted sets, not including elements already existing for which the score was updated.</returns>
        public static long SortedSetAddFun(RedisKey key, SortedSetEntry[] values, int dbIndex = 0, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);
            return connectionMultiplexer.Wait(db.SortedSetAddAsync(key, values, flags));
        }

        /// <summary>
        /// 根据key获取所对应的SortedSet的元素个数
        /// Returns the sorted set cardinality (number of elements) of the sorted set stored at key.
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="min">min，这里默认值-1.0 / 0.0其实也可以写成double.NegativeInfinity</param>
        /// <param name="max">max，这里默认值1.0 / 0.0其实也可以写成double.NegativeInfinity</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <param name="exclude">When performing a range query, by default the start / stop limits are inclusive; however, both can also be specified separately as exclusive</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <returns>the cardinality (number of elements) of the sorted set, or 0 if key does not exist.</returns>
        public static long SortedSetLengFun(RedisKey key, double min = -1.0 / 0.0, double max = 1.0 / 0.0, int dbIndex = 0, Exclude exclude = Exclude.None, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);
            return connectionMultiplexer.Wait(db.SortedSetLengthAsync(key, min, max, exclude, flags));
        }

        /// <summary>
        /// 返回有序集key中，指定区间内的成员。其中成员按score值递增(从小到大)来排序。具有相同score值的成员按字典序来排列。（注意这里是ByRank）
        /// 如果你需要成员按score值递减(score相等时按字典序递减)来排列，请使用ZREVRANGE命令。
        /// Returns the specified range of elements in the sorted set stored at key.
        /// By default the elements are considered to be ordered from the lowest to the
        /// highest score. Lexicographical order is used for elements with equal score.
        ///  Both start and stop are zero-based indexes, where 0 is the first element,
        /// 1 is the next element and so on. They can also be negative numbers indicating
        /// offsets from the end of the sorted set, with -1 being the last element of
        /// the sorted set, -2 the penultimate element and so on.
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <param name="lStop">开始位置</param>
        /// <param name="lStop">结束位置</param>
        /// <param name="order">The direction in which to sequence elements</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <returns>list of elements in the specified range</returns>
        public static RedisValue[] SortedSetRangeByRankFun(RedisKey key, int dbIndex = 0, long lStart = 0, long lStop = -1, Order order = Order.Ascending, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);

            RedisValue[] rv = connectionMultiplexer.Wait(db.SortedSetRangeByRankAsync(key, lStart, lStop, order, flags));
            return rv;
        }

        /// <summary>
        /// 返回有序集key中，指定区间内的成员。其中成员按score值递增(从小到大)来排序。具有相同score值的成员按字典序来排列。（注意这里是ByRank）
        /// 如果你需要成员按score值递减(score相等时按字典序递减)来排列，请使用ZREVRANGE命令。
        /// 这个其实就是：ZRANGE key start stop WITHSCORES，或者ZRANGEBYSCORE key -inf +inf
        /// Returns the specified range of elements in the sorted set stored at key.
        /// By default the elements are considered to be ordered from the lowest to the
        /// highest score. Lexicographical order is used for elements with equal score.
        ///  Both start and stop are zero-based indexes, where 0 is the first element,
        /// 1 is the next element and so on. They can also be negative numbers indicating
        /// offsets from the end of the sorted set, with -1 being the last element of
        /// the sorted set, -2 the penultimate element and so on.
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <param name="lStop">开始位置</param>
        /// <param name="lStop">结束位置</param>
        /// <param name="order">The direction in which to sequence elements</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <returns>list of elements in the specified range</returns>
        public static SortedSetEntry[] SortedSetRangeByRankWithScoresFun(RedisKey key, int dbIndex = 0, long lStart = 0, long lStop = -1, Order order = Order.Ascending, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);

            SortedSetEntry[] ss = connectionMultiplexer.Wait(db.SortedSetRangeByRankWithScoresAsync(key, lStart, lStop, order, flags));

            //List<T> list = new List<T>();
            //foreach (KeyValuePair<RedisValue, double> kv in ss)
            //{
            //    list.Add(JsonConvert.DeserializeObject<T>(kv.Key));
            //}

            return ss;
        }

        /// <summary>
        /// 返回key的有序集合中的分数在min和max之间的所有元素（包括分数等于max或者min的元素）。元素被认为是从低分到高分排序的。（注意这里是ByScore）
        /// Returns the specified range of elements in the sorted set stored at key. By default the elements are considered to be ordered from the lowest to the highest score. 
        /// Lexicographical order is used for elements with equal score. Both start and stop are zero-based indexes, where 0 is the first element, 1 is the next element and so on. 
        /// They can also be negative numbers indicating offsets from the end of the sorted set, with -1 being the last element of the sorted set, -2 the penultimate element and so on.
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <param name="dStart">min，这里默认值double.NegativeInfinity其实也可以写成-1.0 / 0.0</param>
        /// <param name="dStop">max，这里默认值double.NegativeInfinity其实也可以写成1.0 / 0.0</param>
        /// <param name="exclude">When performing a range query, by default the start / stop limits are inclusive; however, both can also be specified separately as exclusive</param>
        /// <param name="order">The direction in which to sequence elements</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <returns>list of elements in the specified score range</returns>
        public static RedisValue[] SortedSetRangeByScoreFun(RedisKey key, int dbIndex = 0, double dStart = double.NegativeInfinity, double dStop = double.PositiveInfinity, Exclude exclude = Exclude.None, Order order = Order.Ascending, long skip = 0, long take = -1, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);

            RedisValue[] rv = connectionMultiplexer.Wait(db.SortedSetRangeByScoreAsync(key, dStart, dStop, exclude, order, skip, take, flags));
            return rv;
        }

        /// <summary>
        /// 返回key的有序集合中的分数在min和max之间的所有元素（包括分数等于max或者min的元素）。元素被认为是从低分到高分排序的。（注意这里是ByScore）
        /// Returns the specified range of elements in the sorted set stored at key. By default the elements are considered to be ordered from the lowest to the highest score. 
        /// Lexicographical order is used for elements with equal score.Both start and stop are zero-based indexes, where 0 is the first element, 1 is the next element and so on. 
        /// They can also be negative numbers indicating offsets from the end of the sorted set, with -1 being the last element of the sorted set, -2 the penultimate element and so on.
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <param name="dStart">min，这里默认值double.NegativeInfinity其实也可以写成-1.0 / 0.0</param>
        /// <param name="dStop">max，这里默认值double.NegativeInfinity其实也可以写成1.0 / 0.0</param>
        /// <param name="exclude">When performing a range query, by default the start / stop limits are inclusive; however, both can also be specified separately as exclusive</param>
        /// <param name="order">The direction in which to sequence elements</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <returns>list of elements in the specified score range</returns>
        public static SortedSetEntry[] SortedSetRangeByScoreWithScoresFun(RedisKey key, int dbIndex = 0, double dStart = double.NegativeInfinity, double dStop = double.PositiveInfinity, Exclude exclude = Exclude.None, Order order = Order.Ascending, long skip = 0, long take = -1, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);

            SortedSetEntry[] ss = connectionMultiplexer.Wait(db.SortedSetRangeByScoreWithScoresAsync(key, dStart, dStop, exclude, order, skip, take, flags));

            //List<T> list = new List<T>();
            //foreach (KeyValuePair<RedisValue, double> kv in ss)
            //{
            //    list.Add(JsonConvert.DeserializeObject<T>(kv.Key));
            //}

            return ss;
        }

        /// <summary>
        /// 移除有序集key中，指定排名(rank)区间内的所有成员。下标参数start和stop都以0为底，0处是分数最小的那个元素。（注意这里是ByRank）
        /// 这些索引也可是负数，表示位移从最高分处开始数。例如，-1是分数最高的元素，-2是分数第二高的，依次类推。
        /// Removes all elements in the sorted set stored at key with rank between start
        /// and stop. Both start and stop are 0 -based indexes with 0 being the element
        /// with the lowest score. These indexes can be negative numbers, where they
        /// indicate offsets starting at the element with the highest score. For example:
        /// -1 is the element with the highest score, -2 the element with the second
        /// highest score and so forth.
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <param name="lStop">开始位置</param>
        /// <param name="lStop">结束位置</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <returns>the number of elements removed.</returns>
        public static long SortedSetRemoveRangeByRankFun(RedisKey key, int dbIndex = 0, long lStart = 0, long lStop = -1, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);
            return connectionMultiplexer.Wait(db.SortedSetRemoveRangeByRankAsync(key, lStart, lStop, flags));
        }

        /// <summary>
        /// 移除有序集key中，所有score值介于dStart和dStop之间(包括等于dStart或dStop)的成员。（注意这里是ByScore）
        /// Removes all elements in the sorted set stored at key with a score between min and max (inclusive by default).
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <param name="dStart">min</param>
        /// <param name="dStop">max</param>
        /// <param name="exclude">When performing a range query, by default the start / stop limits are inclusive; however, both can also be specified separately as exclusive</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <returns>the number of elements removed.</returns>
        public static long SortedSetRemoveRangeByScoreFun(RedisKey key, int dbIndex = 0, double dStart = 0, double dStop = -1, Exclude exclude = Exclude.None, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);
            return connectionMultiplexer.Wait(db.SortedSetRemoveRangeByScoreAsync(key, dStart, dStop, exclude, flags));
        }

        /// <summary>
        /// 模糊搜索指定key所对应的members
        /// The SSCAN command is used to incrementally iterate over set
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="pattern">模糊搜索</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        public static SortedSetEntry[] SortedSetScanFun(RedisKey key, RedisValue pattern, int dbIndex = 0, int pageSize = 10, long cursor = 0, int pageOffset = 0, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);
            IServer server = ConMultiplexerHelper.GetServer(connectionMultiplexer);

            SortedSetEntry[] ss = db.SortedSetScan(key, "*" + pattern + "*", pageSize, cursor, pageOffset, flags).ToArray();

            //List<T> list = new List<T>();
            //foreach (KeyValuePair<RedisValue, double> kv in ss)
            //{
            //    list.Add(JsonConvert.DeserializeObject<T>(kv.Key));
            //}

            return ss;
        }

        /// <summary>
        /// 返回集合 key 中的所有成员。不存在的 key 被视为空集合。(Set、SortedSet通用)
        /// Returns all the members of the set value stored at key.
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <returns>all elements of the set.</returns>
        public static RedisValue[] SortedSetMembersFun(RedisKey key, int dbIndex = 0, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);
            RedisValue[] rv = connectionMultiplexer.Wait(db.SetMembersAsync(key, flags));
            return rv;
        }

        #endregion

        #region List

        /// <summary>
        /// 在列表中的另一个元素之前插入一个元素
        /// Inserts value in the list stored at key either before or after the reference value pivot.  
        /// When key does not exist, it is considered an empty list and no operation is performed.
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="pivot">目标元素</param>
        /// <param name="value">新的元素</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <returns>the length of the list after the insert operation, or -1 when the value pivot was not found.</returns>
        public static long ListInsertBeforeFun(RedisKey key, RedisValue pivot, RedisValue value, int dbIndex = 0, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);
            return connectionMultiplexer.Wait(db.ListInsertBeforeAsync(key, pivot, value, flags));
        }

        /// <summary>
        /// 在列表中的另一个元素之后插入一个元素
        /// Inserts value in the list stored at key either before or after the reference value pivot.  
        /// When key does not exist, it is considered an empty list and no operation is performed.
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="pivot">目标元素</param>
        /// <param name="value">新的元素</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <returns>the length of the list after the insert operation, or -1 when the value pivot was not found.</returns>
        public static long ListInsertAfterFun(RedisKey key, RedisValue pivot, RedisValue value, int dbIndex = 0, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);
            return connectionMultiplexer.Wait(db.ListInsertAfterAsync(key, pivot, value, flags));
        }

        /// <summary>
        /// 移除并且返回 key 对应的 list 的第一个元素。
        /// Removes and returns the first element of the list stored at key.
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <returns>the value of the first element, or nil when key does not exist.</returns>
        public static RedisValue ListLeftPopFun(RedisKey key, int dbIndex = 0, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);
            return connectionMultiplexer.Wait(db.ListLeftPopAsync(key, flags));
        }

        /// <summary>
        /// 移除并返回存于 key 的 list 的最后一个元素。
        /// Removes and returns the last element of the list stored at key.
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <returns>the value of the last element, or nil when key does not exist.</returns>
        public static RedisValue ListRightPopFun(RedisKey key, int dbIndex = 0, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);
            return connectionMultiplexer.Wait(db.ListRightPopAsync(key, flags));
        }

        /// <summary>
        /// 将所有指定的值插入到存于 key 的列表的头部。
        /// Insert the specified value at the head of the list stored at key. If key
        /// does not exist, it is created as empty list before performing the push operations.
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="value">新的元素</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <param name="when">Indicates when this operation should be performed</param>
        /// <returns>the length of the list after the push operations.</returns>
        public static long ListLeftPushFun(RedisKey key, RedisValue value, int dbIndex = 0, When when = When.Always, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);
            return connectionMultiplexer.Wait(db.ListLeftPushAsync(key, value, when, flags));
        }

        /// <summary>
        /// 向存于 key 的列表的尾部插入所有指定的值。
        /// Insert the specified value at the tail of the list stored at key. If key
        /// does not exist, it is created as empty list before performing the push operation.
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="value">新的元素</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <param name="when">Indicates when this operation should be performed</param>
        /// <returns>the length of the list after the push operation.</returns>
        public static long ListRightPushFun(RedisKey key, RedisValue value, int dbIndex = 0, When when = When.Always, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);
            return connectionMultiplexer.Wait(db.ListRightPushAsync(key, value, when, flags));
        }

        /// <summary>
        /// 返回存储在 key 的列表里指定范围内的元素。
        /// Returns the specified elements of the list stored at key. 
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <param name="lStop">开始位置</param>
        /// <param name="lStop">结束位置</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <returns>list of elements in the specified range.</returns>
        public static RedisValue[] ListRangeFun(RedisKey key, int dbIndex = 0, long lStart = 0, long lStop = -1, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);
            return connectionMultiplexer.Wait(db.ListRangeAsync(key, lStart, lStop, flags));
        }

        /// <summary>
        /// 返回存储在 key 里的list的长度。 如果 key 不存在，那么就被看作是空list，
        /// 并且返回长度为 0。 当存储在 key 里的值不是一个list的话，会返回error。
        /// Returns the length of the list stored at key. If key does not exist, 
        /// it is interpreted as an empty list and 0 is returned.
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <returns> the length of the list at key.</returns>
        public static long ListLengthFun(RedisKey key, int dbIndex = 0, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);
            return connectionMultiplexer.Wait(db.ListLengthAsync(key, flags));
        }

        /// <summary>
        /// 从存于 key 的列表里移除前 count 次出现的值为 value 的元素。 
        /// 这个 count 参数通过下面几种方式影响这个操作： 
        /// count 大于 0: 从头往尾移除值为 value 的元素。
        /// count 小于 0: 从尾往头移除值为 value 的元素。 
        /// count 等于 0: 移除所有值为 value 的元素。
        /// Removes the first count occurrences of elements equal to value from the list stored at key. 
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="value">要移除的元素</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <param name="count">如上所述，有三种方式</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <returns>the number of removed elements.</returns>
        public static long ListRemoveFun(RedisKey key, RedisValue value, int dbIndex = 0, long count = 0, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);
            return connectionMultiplexer.Wait(db.ListRemoveAsync(key, value, count, flags));
        }

        /// <summary>
        /// 修剪(trim)一个已存在的 list，这样 list 就会只包含指定范围的指定元素。
        /// start 和 stop 都是由0开始计数的，这里的 0 是列表里的第一个元素（表头），1 是第二个元素，以此类推。
        /// start 和 end 也可以用负数来表示与表尾的偏移量，比如 -1 表示列表里的最后一个元素， -2 表示倒数第二个，等等。
        /// 例如： LTRIM foobar 0 2 将会对存储在 foobar 的列表进行修剪，只保留列表里的前3个元素。
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="lStart">第一个元素的位置</param>
        /// <param name="lStop">最后一个元素的位置</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        public static void ListTrimFun(RedisKey key, long lStart, long lStop, int dbIndex = 0, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);
            connectionMultiplexer.Wait(db.ListTrimAsync(key, lStart, lStop, flags));
        }

        #endregion

        #region Hash

        /// <summary>
        /// 将哈希表 key 中的域 field 的值设为 value。如果 key 不存在，一个新的哈希表被创建并进行 HSET 操作。
        /// 如果域 field 已经存在于哈希表中，旧值将被覆盖。
        /// Sets field in the hash stored at key to value. If key does not exist, a new
        /// key holding a hash is created. If field already exists in the hash, it is overwritten.
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="hashField">域</param>
        /// <param name="value">值</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <param name="when">Indicates when this operation should be performed</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <returns>1 if field is a new field in the hash and value was set. 0 if field already exists in the hash and the value was updated.</returns>
        public static bool HashSetFun(RedisKey key, RedisValue hashField, RedisValue value, int dbIndex = 0, When when = When.Always, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);
            return connectionMultiplexer.Wait(db.HashSetAsync(key, hashField, value, when, flags));
        }

        /// <summary>
        /// 返回哈希表 key 中给定域 field 的值。当给定域不存在或是给定 key 不存在时，返回 nil 。
        /// Returns the value associated with field in the hash stored at key.
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="hashField">域</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <returns>the value associated with field, or nil when field is not present in the hash or key does not exist.</returns>
        public static RedisValue HashSetFun(RedisKey key, RedisValue hashField, int dbIndex = 0, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);
            return connectionMultiplexer.Wait(db.HashGetAsync(key, hashField, flags));
        }

        /// <summary>
        /// 返回哈希表 key 中给定域 field 的值。当给定域不存在或是给定 key 不存在时，返回 nil 。
        /// Returns the values associated with the specified fields in the hash stored at key. 
        /// For every field that does not exist in the hash, a nil value is returned. 
        /// Because a non-existing keys are treated as empty hashes, running
        /// HMGET against a non-existing key will return a list of nil values.
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="hashFields">域</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <returns>list of values associated with the given fields, in the same order as they are requested.</returns>
        public static RedisValue[] HashSetFun(RedisKey key, RedisValue[] hashFields, int dbIndex = 0, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);
            return connectionMultiplexer.Wait(db.HashGetAsync(key, hashFields, flags));
        }

        /// <summary>
        /// 返回哈希表 key 中，所有的域和值。在返回值里，紧跟每个域名(field name)之后是域的值(value)，所以返回值的长度是哈希表大小的两倍。
        /// Returns all fields and values of the hash stored at key.
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <returns>list of fields and their values stored in the hash, or an empty list when key does not exist.</returns>
        public static HashEntry[] HashGetAllFun(RedisKey key, int dbIndex = 0, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);
            return connectionMultiplexer.Wait(db.HashGetAllAsync(key, flags));
        }

        /// <summary>
        /// 返回哈希表 key 中域的数量。
        /// Returns the number of fields contained in the hash stored at key.
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <returns>number of fields in the hash, or 0 when key does not exist.</returns>
        public static long HashLengthFun(RedisKey key, int dbIndex = 0, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);
            return connectionMultiplexer.Wait(db.HashLengthAsync(key, flags));
        }

        /// <summary>
        /// 返回哈希表 key 中的所有域。
        /// Returns all field names in the hash stored at key.
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <returns>list of fields in the hash, or an empty list when key does not exist.</returns>
        public static RedisValue[] HashKeysFun(RedisKey key, int dbIndex = 0, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);
            return connectionMultiplexer.Wait(db.HashKeysAsync(key, flags));
        }

        /// <summary>
        /// 返回哈希表 key 中所有域的值。
        /// Returns all values in the hash stored at key.
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <returns>list of values in the hash, or an empty list when key does not exist.</returns>
        public static RedisValue[] HashValuesFun(RedisKey key, int dbIndex = 0, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);
            return connectionMultiplexer.Wait(db.HashValuesAsync(key, flags));
        }

        /// <summary>
        /// 删除哈希表 key 中的一个或多个指定域，不存在的域将被忽略。
        /// Removes the specified fields from the hash stored at key. Non-existing fields
        /// are ignored. Non-existing keys are treated as empty hashes and this command returns 0.
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="hashField">域</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <returns>The number of fields that were removed.</returns>
        public static bool HashDeleteFun(RedisKey key, RedisValue hashField, int dbIndex = 0, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);
            return connectionMultiplexer.Wait(db.HashDeleteAsync(key, hashField, flags));
        }

        /// <summary>
        /// 删除哈希表 key 中的一个或多个指定域，不存在的域将被忽略。
        /// Removes the specified fields from the hash stored at key. Non-existing fields
        /// are ignored. Non-existing keys are treated as empty hashes and this command returns 0.
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="hashFields">域</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <returns>The number of fields that were removed.</returns>
        public static long HashDeleteFun(RedisKey key, RedisValue[] hashFields, int dbIndex = 0, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);
            return connectionMultiplexer.Wait(db.HashDeleteAsync(key, hashFields, flags));
        }

        /// <summary>
        /// 迭代hash里面的元素，迭代全部
        /// The HSCAN command is used to incrementally iterate over a hash
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <returns>yields all elements of the hash.</returns>
        public static IEnumerable<HashEntry> HashScanFun(RedisKey key, int dbIndex = 0, int pageSize = 10, long cursor = 0, int pageOffset = 0, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);
            return db.HashScan(key, RedisValue.Null, pageSize, cursor, pageOffset, flags);
        }

        /// <summary>
        /// 迭代hash里面的元素，域筛选
        /// The HSCAN command is used to incrementally iterate over a hash
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="pattern">模糊搜索</param>
        /// <param name="dbIndex">数据库序号</param>
        /// <param name="flags">Behaviour markers associated with a given command</param>
        /// <returns>yields all elements of the hash.</returns>
        public static IEnumerable<HashEntry> HashScanFun(RedisKey key, RedisValue pattern, int dbIndex = 0, int pageSize = 10, long cursor = 0, int pageOffset = 0, CommandFlags flags = CommandFlags.None)
        {
            ConnectionMultiplexer connectionMultiplexer = ConMultiplexerHelper.Connection;
            IDatabase db = connectionMultiplexer.GetDatabase(dbIndex);
            return db.HashScan(key, pattern, pageSize, cursor, pageOffset, flags);
        }

        #endregion

        #region 暂时注释掉
        //protected virtual ConnectionMultiplexer Create(
        //    string clientName = null, int? syncTimeout = null, bool? allowAdmin = null, int? keepAlive = null,
        //    int? connectTimeout = null, string password = null, string tieBreaker = null, TextWriter log = null,
        //    bool fail = true, string[] disabledCommands = null, string[] enabledCommands = null,
        //    bool checkConnect = true, bool pause = true, string failMessage = null,
        //    string channelPrefix = null, bool useSharedSocketManager = true, Proxy? proxy = null)
        //{
        //    if (pause) Thread.Sleep(500); // get a lot of glitches when hammering new socket creations etc; pace it out a bit
        //    string configuration = GetConfiguration();
        //    var config = ConfigurationOptions.Parse(configuration);
        //    if (disabledCommands != null && disabledCommands.Length != 0)
        //    {
        //        config.CommandMap = CommandMap.Create(new HashSet<string>(disabledCommands), false);
        //    }
        //    else if (enabledCommands != null && enabledCommands.Length != 0)
        //    {
        //        config.CommandMap = CommandMap.Create(new HashSet<string>(enabledCommands), true);
        //    }

        //    if (Debugger.IsAttached)
        //    {
        //        syncTimeout = int.MaxValue;
        //    }

        //    if (useSharedSocketManager) config.SocketManager = socketManager;
        //    if (channelPrefix != null) config.ChannelPrefix = channelPrefix;
        //    if (tieBreaker != null) config.TieBreaker = tieBreaker;
        //    if (password != null) config.Password = string.IsNullOrEmpty(password) ? null : password;
        //    if (clientName != null) config.ClientName = clientName;
        //    if (syncTimeout != null) config.SyncTimeout = syncTimeout.Value;
        //    if (allowAdmin != null) config.AllowAdmin = allowAdmin.Value;
        //    if (keepAlive != null) config.KeepAlive = keepAlive.Value;
        //    if (connectTimeout != null) config.ConnectTimeout = connectTimeout.Value;
        //    if (proxy != null) config.Proxy = proxy.Value;
        //    var watch = Stopwatch.StartNew();
        //    var task = ConnectionMultiplexer.ConnectAsync(config, log ?? Console.Out);
        //    if (!task.Wait(config.ConnectTimeout >= (int.MaxValue / 2) ? int.MaxValue : config.ConnectTimeout * 2))
        //    {
        //        task.ContinueWith(x =>
        //        {
        //            try
        //            {
        //                GC.KeepAlive(x.Exception);
        //            }
        //            catch
        //            { }
        //        }, TaskContinuationOptions.OnlyOnFaulted);
        //        throw new TimeoutException("Connect timeout");
        //    }
        //    watch.Stop();
        //    Console.WriteLine("Connect took: " + watch.ElapsedMilliseconds + "ms");
        //    var muxer = task.Result;
        //    if (checkConnect)
        //    {
        //        if (!muxer.IsConnected)
        //        {
        //            if (fail) Assert.Fail(failMessage + "Server is not available");
        //            Assert.Inconclusive(failMessage + "Server is not available");
        //        }
        //    }
        //    muxer.InternalError += OnInternalError;
        //    muxer.ConnectionFailed += OnConnectionFailed;
        //    return muxer;
        //}
        #endregion
    }
}
